package org.example.currency;

import static java.util.concurrent.ThreadLocalRandom.current;

import cn.hutool.cron.timingwheel.SystemTimer;
import cn.hutool.cron.timingwheel.TimerTask;
import cn.hutool.cron.timingwheel.TimerTaskList;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

/**
 * @Title : DeductResp
 * @Description: 划扣执行结果上下问题
 * @author: libo@juzishuke.com
 * @date: 2023/12/21 17:59
 * @Version:1.0
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class DeductResp {

    /**
     * 总数量
     */
    private          Long                               total;
    /**
     * 执行完成数量
     */
    private          AtomicLong                         successCnt   = new AtomicLong(0);
    /**
     * 出现异常数量
     */
    private          AtomicLong                         errorCnt     = new AtomicLong(0);
    /**
     * 错误信息
     */
    private volatile ConcurrentHashMap<Integer, String> errorMessage = new ConcurrentHashMap<>();

    public static void main(String[] args) {
        int total = 10;
        NoticeUtil noticeUtil = new NoticeUtil();
        //        DeductResp deductResp = DeductResp.builder().total((long) total)
        //                .successCnt(new AtomicLong(0)).errorCnt(new AtomicLong(0))
        //                .errorMessage(new ConcurrentHashMap<>()).build();
        DeductResp deductResp = new DeductResp();
        deductResp.setTotal((long) total);
        CountDownLatch countDownLatch = new CountDownLatch(total);
        ExecutorService executorService = new ThreadPoolExecutor(10, 100, 1000L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>());
        for (int i = 0; i < total; i++) {
            int finalI = i;
            executorService.submit(() -> {
                try {
                    TimeUnit.SECONDS.sleep(current().nextInt(1));
                    noticeUtil.notice(finalI);
                    //                    if (!RandomUtil.randomBoolean()) {
                    //                        throw new Exception(String.valueOf(finalI));
                    //                    }
                    deductResp.getSuccessCnt().getAndIncrement();
                } catch (Exception e) {
                    e.printStackTrace();
                    deductResp.getErrorCnt().getAndIncrement();
                    deductResp.getErrorMessage().put(finalI, e.getMessage());
                } finally {
                    //                    System.out.print(finalI+" ");
                    countDownLatch.countDown();
                }
            });
        }
        System.out.println(deductResp.toString());
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            //            executorService.shutdown();
        }
        System.out.println();
        System.out.println(deductResp.errorMessage.size());
        System.out.println(deductResp.toString());
        StringBuilder sb = new StringBuilder();
        deductResp.errorMessage.values().stream().forEach(e -> sb.append(e).append("\n"));
        System.out.println(deductResp.errorMessage.values());
    }
}

class NoticeUtil {

    //    private TimingWheel timingWheel;

    private SystemTimer systemTimer;

    private final ConcurrentHashMap<Integer, TimerTask>                    hashMap    = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<Integer, ArrayList<Integer>>           datas      = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<Integer, LinkedBlockingDeque<Integer>> data2s     = new ConcurrentHashMap<Integer, LinkedBlockingDeque<Integer>>();
    private final DelayQueue<TimerTaskList>                                delayQueue = new DelayQueue<>();

    public NoticeUtil() {
        //        this.timingWheel = new TimingWheel(1, 10, delayQueue::offer);
        systemTimer = new SystemTimer();
        systemTimer.start();
    }

    public void notice(int finalI) {
        Integer key = finalI % 2;
        if (hashMap.get(key) == null) {
            synchronized (hashMap) {
                if (hashMap.get(key) == null) {
                    System.out.println("put finalI : " + finalI);
                    TimerTask timerTask = new TimerTask(() -> {

                        ArrayList<Integer> d = datas.remove(key);
                        System.out.println("TimeTask:" + key + " : " + d.toString());
                        hashMap.remove(key);
                    }, 200);
                    hashMap.put(key, timerTask);
                    systemTimer.addTask(timerTask);
                    ArrayList<Integer> d = new ArrayList<>();
                    d.add(finalI);
                    datas.put(key, d);
                } else {
                    System.out.println("add finalI : " + finalI);
                    datas.get(key).add(finalI);
                    //                    hashMap.get(key).getTask().run();
                }
            }
        } else {
            System.out.println("add finalI : " + finalI);
            //            System.out.println("add finaI " + finalI + " key " + key);
            datas.get(key).add(finalI);
            //            hashMap.get(key).getTask().run();
        }
    }
}
